package org.ooda.distributedsys.functionmodule.function;

import com.mathworks.toolbox.javabuilder.MWArray;
import com.mathworks.toolbox.javabuilder.MWClassID;
import com.mathworks.toolbox.javabuilder.MWNumericArray;
import main_3Filters.main3_Filters;
import org.ooda.distributedsys.functionmodule.common.ResponseHandler;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.*;

/**
 * @program: distributedSys
 * @description: 态势统一控制器
 * @author: Aprilies
 * @create: 2023-03-03 15:56
 **/

@RestController
@RequestMapping("/unifiedsituation/")
public class UnifiedSituationController {

    private final Queue<Runnable> requestQueue = new LinkedList<>();

    private boolean isProcessingRequest = false;

    /**
     * check main3filters params is validate, the rule is:
     * 1, M_rader >= 1 && M_rader <= 10
     * 2, M_infrared >= 1 && M_infrared <= 10
     * 3, M_laser >= 1 && M_laser <= 10
     * 4, T >= 0.01 && T <= 1
     * 5, MC >= 20 && MC <= 150
     * 6, oristate.length == 6
     * @param M_rader
     * @param M_infrared
     * @param M_laser
     * @param T
     * @param MC
     * @param oristate
     * @return
     */
    private boolean checkTheParamsIsValidate(Integer M_rader, Integer M_infrared, Integer M_laser, Double T, Double MC, double[] oristate){
        if (M_rader < 1 || M_rader > 10 || M_infrared < 1 || M_infrared > 10 || M_laser < 1 || M_laser > 10)
            return false;
        if (T < 0.01 || T > 1)
            return false;
        if (MC > 150 || MC < 20)
            return false;
        if (oristate.length != 6)
            return false;
        return true;
    }

    private final static ArrayList<String> FILTER_NAME = new ArrayList<>(Arrays.asList("EKF","UKF","CKF","DEKF","DUKF","DCKF","HDUKF","HDCKF"));

    /**
     * 得到6种滤波算法的结果
     * POST /unifiedsituation/main3filters
     */

    @PostMapping("main3filters")
    public DeferredResult<ResponseEntity<?>> main3filters(@RequestParam(value = "M_rader", defaultValue = "3") Integer M_rader,
                                                           @RequestParam(value = "M_infrared", defaultValue = "5") Integer M_infrared,
                                                           @RequestParam(value = "M_laser", defaultValue = "4") Integer M_laser,
                                                           @RequestParam(value = "T",defaultValue = "0.1") Double T,
                                                           @RequestParam(value = "MC", defaultValue = "100") Double MC,
                                                           @RequestParam(value = "oristate", defaultValue = "80,2,80,2,80,2") double[] oristate){
        if(!checkTheParamsIsValidate(M_rader, M_infrared, M_laser, T, MC, oristate)){
            DeferredResult<ResponseEntity<?>> deferedResult = new DeferredResult<>();
            deferedResult.setResult(ResponseHandler.generateResponse("params is not validate", HttpStatus.BAD_REQUEST, null));
            return deferedResult;
        }

        DeferredResult<ResponseEntity<?>> deferedResult = new DeferredResult<>();

        // 包装矩阵变量
        Runnable requestTask = () -> {
            Object[] objects = new Object[0];
            try {
                MWNumericArray MW_oristate = new MWNumericArray(oristate, MWClassID.DOUBLE);
                MWNumericArray MW_M_rader = new MWNumericArray(M_rader, MWClassID.INT32);
                MWNumericArray MW_M_infrared = new MWNumericArray(M_infrared, MWClassID.INT32);
                MWNumericArray MW_M_laser = new MWNumericArray(M_laser, MWClassID.INT32);
                MWNumericArray MW_T = new MWNumericArray(T, MWClassID.DOUBLE);
                MWNumericArray MW_MC = new MWNumericArray(MC, MWClassID.DOUBLE);
                // 创建MATLAB程序，得到main3filters函数的输出
                main3_Filters main3Filter = new main3_Filters();
                objects = main3Filter.main_3Filters(4, MW_M_rader, MW_M_infrared, MW_M_laser, MW_T, MW_MC, MW_oristate);
                // 释放资源
                MWArray.disposeArray(MW_oristate);
                MWArray.disposeArray(MW_M_rader);
                MWArray.disposeArray(MW_M_infrared);
                MWArray.disposeArray(MW_M_laser);
                MWArray.disposeArray(MW_T);
                MWArray.disposeArray(MW_MC);
                main3Filter.dispose();
            } catch (Exception e) {
                e.printStackTrace();
                ResponseEntity<?> response =  ResponseHandler.generateResponse("function runtime error", HttpStatus.INTERNAL_SERVER_ERROR, null);
                deferedResult.setResult(response);
            }
            // 将得到的输出转换数据格式
            // 处理position和velocity折线图数据
            HashMap<String, Object> rms_position = new HashMap<>();
            HashMap<String, Object> rms_velocity = new HashMap<>();
            // 处理position和velocity得到的rms数据
            HashMap<String, Object> _rms_position = new HashMap<>();
            HashMap<String, Object> _rms_velocity = new HashMap<>();
            double[][] positionArray = (double[][]) ((MWNumericArray) (objects[0])).toDoubleArray();
            double[][] velocityArray = (double[][]) ((MWNumericArray) (objects[1])).toDoubleArray();
            for (int i = 0; i < positionArray[0].length; i++) {
                ArrayList<Double> position = new ArrayList<>();
                ArrayList<Double> velocity = new ArrayList<>();
                double positionDouble = (double) 0;
                double velocityDouble = (double) 0;
                for (int j = 0; j < positionArray.length; j++) {
                    position.add(positionArray[j][i]);
                    velocity.add(velocityArray[j][i]);
                    positionDouble += positionArray[j][i];
                    velocityDouble += velocityArray[j][i];
                }
                rms_position.put(FILTER_NAME.get(i), position);
                rms_velocity.put(FILTER_NAME.get(i), velocity);
                _rms_position.put(FILTER_NAME.get(i), positionDouble / positionArray.length);
                _rms_velocity.put(FILTER_NAME.get(i), velocityDouble / velocityArray.length);
            }
            // 处理increase数据
            HashMap<String, Double> increase = new HashMap<>();
            double[] increaseArray = ((MWNumericArray) (objects[2])).getDoubleData();
            for (int i = 0; i < increaseArray.length; i++) {
                increase.put(FILTER_NAME.get(i), increaseArray[i]);
            }
            // 处理mean_increase数据
            double mean_increase = ((MWNumericArray) (objects[3])).getDouble();
            // 将数据包装进映射中
            HashMap<String, Object> result = new HashMap<>();
            HashMap<String, Object> secondFloor = new HashMap<>();
            secondFloor.put("position", rms_position);
            secondFloor.put("velocity", rms_velocity);
            secondFloor.put("rms_position", _rms_position);
            secondFloor.put("rms_velocity", _rms_velocity);
            result.put("rms", secondFloor);
            result.put("increase", increase);
            result.put("mean_increase", mean_increase);
            ResponseEntity<?> response = ResponseHandler.generateResponse("success", HttpStatus.OK, result);
            deferedResult.setResult(response);
            // Send the response
            synchronized (this) {
                isProcessingRequest = false;
                if (!requestQueue.isEmpty()) {
                    // If there are pending requests, process the next one
                    Runnable nextRequest = requestQueue.poll();
                    nextRequest.run();
                }
            }
        };
        if (isProcessingRequest) {
            // If another request is already being processed, enqueue the current request
            requestQueue.offer(requestTask);
        } else {
            // Process the current request
            isProcessingRequest = true;
            requestTask.run();
        }
        return deferedResult;
    }
}
